#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include "cpu.h"
#include "bus.h"
#include "arm.h"
#include "symtbl.h"
#include "log.h"

bool on=0,x=0;
__u32 bk_addr;
__u32 buf_addr;
bool CCPU::do_clock()
{

	char buffer[1024];

	//
	//
	//

	int i;
	char *sym;	

	__u32 psr=regfile.prf[CPSR];

	if(Thumb(psr))
	{
		THUMB_INSN_INFO thumb_insn;
		regfile.dump_thumb_base_state(buffer);
		printf("%s\n",buffer);

		return 0;
		/*
		dump_arm_bank_state(buffer);
		printf("%s\n",buffer);
		dump_arm_spsr_state(buffer);
		printf("%s\n",buffer);
		*/
		thumb_insn.code=bus_read_short(regfile.prf[PC]);



		i=sprintf(buffer,"%08X %02X %02X ",regfile.prf[PC],
			thumb_insn.byte[1],
			thumb_insn.byte[0]
		);


		i+=disasm_thumb(buffer+i,thumb_insn,regfile.prf[PC]);
		buffer[i]=0;
		printf("%s\n",buffer);
#if 1
		if(regfile.prf[PC]==0x80178) 
			printf("");
		exec_thumb();

#else
		regfile.prf[PC]+=4;
#endif
	}
	else
	{
		if(regfile.prf[PC]==0xBF1A0740)//
		{
			regfile.prf[R0]=0;
		}else
		if(regfile.prf[PC]==0xBF0ABFEC)//
		{
			regfile.prf[CPSR]^=(1<<CPSR_BIT_Z);
		}else
		if(regfile.prf[PC]==0xbf096dd8)//BF1A81C8
		{
			//regfile.dump_arm_base_state(buffer);
			//log(buffer);

			if((regfile.prf[7]>>24)==0xbf)
			{
				regfile.prf[1] |=0xbf000000;
			}
			//dump_mem(regfile.read_register(R0),0x100);

			//on=true;
		}else
		if(regfile.prf[PC]==0xBF096930)
		{
			buf_addr=0;
			//on=true;
		}else
		if(regfile.prf[PC]==0xbf0de564)
		{
			//regfile.dump_arm_base_state(buffer);
			//log(buffer);
			//dump_stack();
			//dump_string(regfile.read_register(R1));
			//dump_mem(regfile.read_register(R3),0x10);
			//printf("");
			bk_addr=regfile.read_register(R14);
			buf_addr=0;
			//x=true;
	
		}	else
		//if(regfile.prf[PC]==0xbf0dec34)
		//{
		//	//regfile.dump_arm_base_state(buffer);
		//	//log(buffer);
		//	//dump_stack();
		//	//dump_string(regfile.read_register(R2));
		//	//dump_mem(regfile.read_register(R3),0x10);
		//	//printf("");
		//	bk_addr=regfile.read_register(R14);
		//	buf_addr=regfile.read_register(R0);
		//	on=true;
		//}	else
		//if(regfile.prf[PC]==0xbf0ac61c)//bf1a6744:strcpy
		//{
		//	//regfile.dump_arm_base_state(buffer);
		//	//log(buffer);
		//	//dump_stack();
		//	//dump_string(regfile.read_register(R2));
		//	//dump_mem(regfile.read_register(R1),regfile.read_register(R2));
		//	printf("=============\n");
		//	bk_addr=regfile.read_register(R14);
		//	buf_addr=regfile.read_register(R1);
		//	on=true;

		//}	else
		//if(regfile.prf[PC]==0xbf0c25c8)//
		//{
		//	regfile.dump_arm_base_state(buffer);
		//	log(buffer);
		//	//dump_stack();
		//	//dump_string(regfile.read_register(R0));
		//	//dump_mem(regfile.read_register(R0),0x100);
		//	//printf("");
		//	bk_addr=regfile.read_register(R14);
		//	buf_addr=0;
		//	on=true;
		//	log("\n***********>>>>>\n");
		//}	else
		if(regfile.prf[PC]==0xbf0800c0)//
		{
		//	printf("");
			regfile.prf[R6]+=0xc0000000;
		    regfile.prf[R6]-=0xbf000000;
			//on=true;
		}else
		if(regfile.prf[PC]==0xBF0CD004)//
		{
			//printf("r2:%x",regfile.read_register(R2));
			//printf("r3:%x\n",regfile.read_register(R3));
			regfile.write_register(R2,0);
			regfile.write_register(R3,0);
			//on=true;
		}else
		//if(regfile.prf[PC]==0xBF0CD014)//
		//{
		////	printf("");
		//	//printf("r3:%x\n",regfile.read_register(R3));
		//	//on=true;
		//}else
		//if(regfile.prf[PC]==0xBF0CD04C)//
		//{
		////	printf("");
		//	printf("r3:%x\n",regfile.read_register(R3));
		//	x=true;
		//}else
		if(regfile.prf[PC]==bk_addr)//
		{
			if(buf_addr!=NULL)
			dump_string(buf_addr);
			//on=false;
		//	
		}
		//else if(regfile.read_register(R8)==0) on=true;
		//else on=false;


		if(read_insn(regfile.prf[PC],&arm_insn.code))
		{
				// fault:abort
	
			


		

			//else
			//	on=false;

			//if(regfile.prf[PC]==0xc5d8+0x87f64000) 
			//{
				//on=true;
			//}
			 
			if(x)
			{
			sym=sym_lookup(regfile.prf[PC]);
			if(sym)
				log("%s:\n",sym);
			}

			if(on)
			{

			regfile.dump_arm_base_state(buffer);
			log("%s",buffer);
			

			/*
			dump_arm_bank_state(buffer);
			printf("%s\n",buffer);
			dump_arm_spsr_state(buffer);
			printf("%s\n",buffer);
			*/


			
			//else i=0;

			i=disasm_arm(buffer+i,arm_insn,regfile.prf[PC]);
			buffer[i]=0;
			log("%s\n",buffer);
			
	}

	#if 1
			//if(regfile.prf[PC]==0x2b4f0+0x87f64000) //exit(0);
			//{
			//	printf("strcmp:%x(%c),%x(%c)\n",
			//		regfile.prf[R0],bus_read_byte(regfile.prf[R0]),
 		//			regfile.prf[R1],bus_read_byte(regfile.prf[R1]));
			//	//on=true;
			//}

			//if(regfile.prf[Bank_R13(state.mode)])
			//	printf("sp:%x\n",regfile.prf[Bank_R13(state.mode)]);

			if(!exec_arm())
			{
				log("fault at:%x",regfile.prf[PC]);
				return false;
			}
			else
			{
#ifdef UBOOT
				if(regfile.prf[PC]==0xb0) //exit(0);
					regfile.prf[R0]=0;
				if(regfile.prf[PC]==0x94) //exit(0);z
					regfile.prf[R2]=0;		
				if(regfile.prf[PC]==0x128) //exit(0);
					regfile.prf[R3]=0;
#endif
			}
			//if(regfile.prf[PC]==0xc1b0+0x87f64000) //exit(0);
			//{
			//	//regfile.prf[R0]+=(1<<31);
			//	__u32 p=regfile.prf[R0];
			//	for(int i=0;i<regfile.prf[R1];i++)
			//	{
			//		printf("%d %x\n",i,bus_read_int(p));
			//		p+=24;
			//	}
			//	on=true;
			//}
	#else
			regfile.prf[PC]+=4;
	#endif
		}
		else
		{
			log("stop:%x\n",regfile.prf[PC]);
			while(!_kbhit()||_getch()!=' ') ;
			return false;
		}
		//
		// poll interrupt
		//
		bool poll_irq();
		bool poll_fiq();

		if(!TEST_BIT(regfile.prf[CPSR],CPSR_BIT_F)
			&&0
			/*&&poll_fiq()*/)
		{
			//log("fiq:\n");
			//exec_fiq();
		}
		if(!TEST_BIT(regfile.prf[CPSR],CPSR_BIT_I)
			&&poll_irq())
		{
			//on=true;
			//log("irq:\n");
			exec_irq();
		__u32 jiffies;
		mmu.read_int(0xc00198a8,&jiffies);
		jiffies+=0x100;
		mmu.write_int(0xc00198a8,jiffies);
		if(jiffies<=0x150)
		{
			mmu.read_int(0xc00198ac,&jiffies);
		jiffies+=0x100;
		mmu.write_int(0xc00198ac,jiffies);
		}

		}


	}
	return true;
}



bool CCPU::read_byte (__u32 address,__u8 *p_dat)
{
	return mmu.read_byte(address,p_dat);
	
}

bool CCPU::read_short(__u32 address,__u16 *p_dat)
{
	// if cross dword boundary, 
	if((address&3)==3)
	{
		__u8 b1,b2;


		if(read_byte(address,&b1)&&read_byte(address+1,&b2))
		//if(little_endian)
		{
			*p_dat=(b2<<8)|b1;
			return true;
		}
		return false;
	}
	else
	return mmu.read_short(address,p_dat);
}
bool CCPU::read_int(__u32 address,__u32 *p_dat)
{
	// if cross dword boundary
	if((address&3)!=0)
	{
		__u8 b1,b2,b3,b4;


		if(read_byte(address,&b1)
		&&read_byte(address+1,&b2)
		&&read_byte(address+2,&b3)
		&&read_byte(address+3,&b4))
		//if(little_endian)
		{
			*p_dat=(b4<<24)|(b3<<16)|(b2<<8)|b1;
			return true;
		}
		return false;
	}
	else
	
	return mmu.read_int(address,p_dat);
}

bool  CCPU::read_insn(__u32 address,__u32*p_dat)
{
	assert(!(address&3));

	return mmu.read_insn(address,p_dat);
}
bool CCPU::write_byte (__u32 address,__u8  dat)
{
	return mmu.write_byte(address,dat);
}
bool  CCPU::write_short(__u32 address,__u16 dat)
{
	// if cross dword boundary
	if((address&3)!=0)
	{
		__u8 b1,b2,b3,b4;
		//if(little_endian)
		{
			b1=(__u8)dat;
			b2=(__u8)(dat>>8);
		}

		return
			write_byte(address,b1)
			&&write_byte(address+1,b2);

	}
	else
	return mmu.write_short(address,dat);
}
bool  CCPU::write_int(__u32 address,__u32 dat)
{
	// if cross dword boundary
	if((address&3)!=0)
	{
		__u8 b1,b2,b3,b4;
		//if(little_endian)
		{
			b1=(__u8)dat;
			b2=(__u8)(dat>>8);
			b3=(__u8)(dat>>16);
			b4=(__u8)(dat>>24);
		}

		return 
			write_byte(address,b1)
			&&write_byte(address+1,b2)
			&&write_byte(address+2,b3)
			&&write_byte(address+3,b4);
	}
	else
	
	return mmu.write_int(address,dat);
}